using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Dapper;


namespace DapperExtensions
{
    public static partial class SqlMapperExtensions
    {       
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TReturn>(cnn, ctx.CommandText, types, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Execute(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static int Execute(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.Execute(cnn, command);
        }
        
        public static object ExecuteScalar(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.ExecuteScalar(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static T ExecuteScalar<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.ExecuteScalar<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static object ExecuteScalar(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.ExecuteScalar(cnn, command);
        }
        
        public static T ExecuteScalar<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.ExecuteScalar<T>(cnn, command);
        }
        
        public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.ExecuteReader(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.ExecuteReader(cnn, command);
        }
        
        public static IDataReader ExecuteReader(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.ExecuteReader(cnn, command, commandBehavior);
        }
        
        public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query(cnn, ctx.CommandText, ctx.Parameters, transaction, buffered, commandTimeout, commandType);
        }
        
        public static dynamic QueryFirst(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirst(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static dynamic QueryFirstOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirstOrDefault(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static dynamic QuerySingle(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingle(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static dynamic QuerySingleOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingleOrDefault(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, buffered, commandTimeout, commandType);
        }
        
        public static T QueryFirst<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirst<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static T QueryFirstOrDefault<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirstOrDefault<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static T QuerySingle<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingle<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static T QuerySingleOrDefault<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingleOrDefault<T>(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static IEnumerable<object> Query(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query(cnn, type, ctx.CommandText, ctx.Parameters, transaction, buffered, commandTimeout, commandType);
        }
        
        public static object QueryFirst(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirst(cnn, type, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static object QueryFirstOrDefault(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryFirstOrDefault(cnn, type, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static object QuerySingle(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingle(cnn, type, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static object QuerySingleOrDefault(this IDbConnection cnn, Type type, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QuerySingleOrDefault(cnn, type, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static IEnumerable<T> Query<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.Query<T>(cnn, command);
        }
        
        public static T QueryFirst<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.QueryFirst<T>(cnn, command);
        }
        
        public static T QueryFirstOrDefault<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.QueryFirstOrDefault<T>(cnn, command);
        }
        
        public static T QuerySingle<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.QuerySingle<T>(cnn, command);
        }
        
        public static T QuerySingleOrDefault<T>(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.QuerySingleOrDefault<T>(cnn, command);
        }
        
        public static Dapper.SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.QueryMultiple(cnn, ctx.CommandText, ctx.Parameters, transaction, commandTimeout, commandType);
        }
        
        public static Dapper.SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command)
        {
            var ctx = new DapperContext(command.CommandText, command.Parameters);
            OnExecuting(ctx);
            command = command.Clone(command.CommandText, command.Parameters); 
            return Dapper.SqlMapper.QueryMultiple(cnn, command);
        }
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            var ctx = new DapperContext(sql, param);
            OnExecuting(ctx);
            return Dapper.SqlMapper.Query<TFirst, TSecond, TThird, TReturn>(cnn, ctx.CommandText, map, ctx.Parameters, transaction, buffered, splitOn, commandTimeout, commandType);
        }
        
    }
}